#pragma once

#include <cstdint>
#include <ctime>
#include <unordered_map>

namespace rpc {

class MethodCallStatistics;
class ServiceCallStatistics;

/**
 * {Method ID, Statistics}.
 */
using MethodStatistics =
    std::unordered_map<std::uint32_t, MethodCallStatistics *>;

/**
 * {Service UUID, Statistics}.
 */
using ServiceStatistics =
    std::unordered_map<std::uint64_t, ServiceCallStatistics *>;

/**
 * The statistics of each method call.
 */
class MethodCallStatistics {
public:
  /**
   * dtor.
   *
   */
  virtual ~MethodCallStatistics() {}
  /**
   * Get method ID.
   *
   * \return
   */
  virtual std::uint32_t getMethodID() const noexcept = 0;
  /**
   * Get current QPS.
   *
   * \return
   */
  virtual std::uint32_t getQPS() const noexcept = 0;
  /**
   * Get peak QPS.
   *
   * \return
   */
  virtual std::uint32_t getPeakQPS() const noexcept = 0;
  /**
   * Get total call count including successful and failure callings.
   *
   * \return
   */
  virtual std::uint32_t getCallCount() const noexcept = 0;
  /**
   * Get successful calling count.
   *
   * \return
   */
  virtual std::uint32_t getCallSuccessCount() const noexcept = 0;
  /**
   * Get minimum cost in microseconds.
   *
   * \return
   */
  virtual std::time_t getMinCost() const noexcept = 0;
  /**
   * Get maximum cost in microseconds.
   *
   * \return
   */
  virtual std::time_t getMaxCost() const noexcept = 0;
  /**
   * Get AVG. cost in microseconds
   *
   * \return
   */
  virtual std::time_t getAvgCost() const noexcept = 0;

  virtual const std::string& getMethodFullName() const noexcept = 0;
};

/**
 * The statistics of each service.
 */
class ServiceCallStatistics {
public:
  /**
   * dtor.
   *
   */
  virtual ~ServiceCallStatistics() {}
  /**
   * Get service UUID.
   *
   * \return
   */
  virtual std::uint64_t getUUID() const noexcept = 0;
  /**
   * Get {Method ID, method stat}.
   *
   * \return
   */
  virtual const MethodStatistics &getMethodStatistics() const noexcept = 0;
  /**
   * Get method stat.
   *
   * \param methodID Method ID
   * \return
   */
  virtual const MethodCallStatistics *
  getMethodCallStatistics(std::uint32_t methodID) const noexcept = 0;
  /**
   * Get current QPS.
   *
   * \return
   */
  virtual std::uint32_t getQPS() const noexcept = 0;
  /**
   * Get peak QPS.
   *
   * \return
   */
  virtual std::uint32_t getPeakQPS() const noexcept = 0;
  /**
   * Get total call count including successful and failure callings.
   *
   * \return
   */
  virtual std::uint32_t getCallCount() const noexcept = 0;
  /**
   * Get successful calling count.
   *
   * \return
   */
  virtual std::uint32_t getCallSuccessCount() const noexcept = 0;
  /**
   * Get minimum cost in microseconds.
   *
   * \return
   */
  virtual std::time_t getMinCost() const noexcept = 0;
  /**
   * Get maximum cost in microseconds.
   *
   * \return
   */
  virtual std::time_t getMaxCost() const noexcept = 0;
  /**
   * Get AVG. cost in microseconds
   *
   * \return
   */
  virtual std::time_t getAvgCost() const noexcept = 0;
};

/**
 * The statistics of all stub service.
 */
class StubCallStatistics {
public:
  /**
   * dtor.
   *
   */
  virtual ~StubCallStatistics() {}

  /**
   * Check healthy.
   *
   * \param uuid Service UUID
   * \param queueSize Current queue size of stub call
   * \param tick Current tick in microseconds
   * \return true for good, false for overload
   */
  virtual bool checkHealthy(std::uint64_t uuid, std::uint32_t queueSize,
                            std::time_t tick) = 0;
  /**
   * Get the stat of all method.
   *
   * \param uuid Service UUID
   * \return {Method ID, method stat}
   */
  virtual const ServiceCallStatistics *
  getServiceCallStatistics(std::uint64_t uuid) const noexcept = 0;

  /**
   * Get the stat of all service.
   *
   * \return {Service UUID, service stat}
   */
  virtual const ServiceStatistics *getServiceStatistics() const noexcept = 0;

  /**
   * Get the stat of method.
   *
   * \param uuid Service UUID
   * \param methodID Method ID
   * \return Method stat
   */
  virtual const MethodCallStatistics *
  getMethodCallStatistics(std::uint64_t uuid,
                          std::uint32_t methodID) const noexcept = 0;

  /**
   * Get the stat of service.
   *
   * \param uuid Service UUID
   * \return Service stat
   */
  virtual const MethodStatistics *
  getMethodStatistics(std::uint64_t uuid) const noexcept = 0;
};

/**
 * Get the global instance of statistics.
 */
extern StubCallStatistics *getStatistic();

} // namespace rpc
